﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text;
using Microsoft.Deployment.WindowsInstaller;
using Microsoft.Deployment.Compression;
using Microsoft.Deployment.WindowsInstaller.Linq;
using Microsoft.Deployment.WindowsInstaller.Package;

namespace MsiValidator
{
    class MsiValidator
    {
        public static CompressionLevel compressionLevel = CompressionLevel.Normal;
        public static string tempFolder = Path.GetTempPath() + "MsiValidator";

        public static string InsertProperties(Database db, string strTableName, string propertyName, string value)
        {
            string strQuery = "SELECT * FROM " + strTableName + " WHERE Property = '" + propertyName + "'";
            if (db.IsTablePersistent(strTableName) == true)
            {
                View view = db.OpenView(strQuery);
                view.Execute();
                foreach (var record in view) using (record)
                {
                    Console.WriteLine("{0} = {1}", record.GetString("Property"), record.GetString("Value"));
                    if (!String.Equals(record.GetString(2), value, StringComparison.Ordinal))
                    {
                        return propertyName + " property should have value: " + value;
                    }
                    else return null;
                }
            }
            return "Missing " + propertyName + " property";
        }

        public static void Recompress(string msiFilePath, bool internalCab)
        {
            string cabName = Path.GetFileNameWithoutExtension(msiFilePath) + ".cab";
            string msiDir = Path.GetDirectoryName(msiFilePath);

            if (internalCab == true)
            {
                cabName = "#Data1.cab";
            }

            using (InstallPackage pkg = new InstallPackage(msiFilePath, DatabaseOpenMode.Transact))
            {
                //get list of external cabs from the Media table
                //string strQuery = "SELECT Cabinet FROM Media WHERE Cabinet LIKE '[^*]%.cab'";
                string strQuery = "SELECT Cabinet FROM Media";
                IList<string> cabArray = pkg.ExecuteStringQuery(strQuery);

                pkg.WorkingDirectory = tempFolder;
                pkg.CompressionLevel = compressionLevel;
                pkg.Consolidate(cabName);
                pkg.SummaryInfo.Close();
                pkg.Commit();
                System.GC.Collect();

                //delete external cabs
                foreach (string cab in cabArray)
                {
                    if (cab[0] != '#')
                    {
                        if (File.Exists(msiDir + "\\" + cab))
                            File.Delete(msiDir + "\\" + cab);
                    }
                }
                if (internalCab == false)
                {
                    //copy new single external cab
                    if (File.Exists(tempFolder + "\\" + cabName))
                    {
                        File.Copy(tempFolder + "\\" + cabName, msiDir + "\\" + cabName, true);
                        File.Delete(tempFolder + "\\" + cabName);
                    }
                }
            }

            //delete temporary folder
            Directory.Delete(tempFolder + "\\WITEMP", true);

        }

    }
}
